﻿using LightCAD.Core.Elements;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using LightCAD.MathLib;
using System.Linq;
using LightCAD.Core.Element3d;

namespace LightCAD.Core
{
    public partial class LcDocument
    {

        public LcDocument()
        {
            this.IdCreator = new IdCreator();
        }

        public string Uuid { get; set; }
        [JsonIgnore]
        public IdCreator IdCreator { get; private set; }

        [JsonIgnore]
        public string FilePath { get; set; }

        public LcDocumentInfo Info { get; set; }

        public LcProjectInfo ProjectInfo { get; set; }

        public Vector2 InsertPoint { get; set; }
        public Vector2 PrePoint { get; set; }

        /// <summary>
        /// 文档是否处于隔离状态，隐藏和隔离命令后的状态
        /// </summary>
        public bool IsIsolateStatus { get; set; }
        public ElementTypeCollection UsedTypes { get; internal set; } = new ElementTypeCollection();

        public ObjectPropertiesDefinitionMap ObjectPropertiesMap { get; internal set; }
        public LcPluginDefinitionMap PluginMap { get; internal set; }
        public ComponentCollection Components { get; internal set; } = new ComponentCollection();


        [JsonInclude]
        public UCSCollection UCSs { get; internal set; }

        //[JsonInclude]
        //public ElementStyleCollction Styles { get; internal set; }

        [JsonInclude]
        public TextStyleCollection TextStyles { get; internal set; }

        [JsonInclude]
        public LcBlockCollection Blocks { get; internal set; } = new LcBlockCollection();

        [JsonInclude]
        public XrefCollection Xrefs { get; internal set; }

        //[JsonInclude]
        //public GroupCollection Groups { get; internal set; }

        [JsonInclude]
        public LayerCollection Layers { get; internal set; } = new LayerCollection();

        [JsonInclude]
        public LcLineTypeCollection LineTypes { get; internal set; } = new LcLineTypeCollection();

        //[JsonInclude]
        //public ViewCollection Views { get; internal set; }

        [JsonInclude]
        public LayoutCollection Layouts { get; internal set; }


        [JsonInclude]
        public BuildingCollection Buildings { get; internal set; } = new BuildingCollection();

        [JsonInclude]
        public LcDrawingFrameCollection DrawingFrames { get; internal set; } = new LcDrawingFrameCollection();

        [JsonInclude]
        public SolidProfileCollection Profiles { get; internal set; }

        [JsonInclude]
        public LcModelSpace ModelSpace { get; internal set; }//->DrawingSpace

        [JsonInclude]
        public LcPaperSpace PaperSpace { get; internal set; }

        //Model3DSpace

        //View3DSpace

        public LcLayer ActiveLayer { get; set; }
        public LcLayout ActiveLayout { get; set; }
        public LcViewport ActiveViewport { get; set; }
        public ActiveSpace ActiveSpace { get; set; }
        public LcUCS ActiveUCS { get; set; }

        public string Color { get; set; } = ValueFrom.ByLayer;

        public string Transprence { get; set; } = ValueFrom.ByLayer;

        public ResourceCollection Resources { get; set; }

        /// <summary>
        /// //搜索DrawingSpace,PaperSpace获得所有使用过的类型
        /// </summary>
        public void RefreshUsedTypes()
        {

        }
        /// <summary>
        /// 统一创建文档模型的对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T CreateObject<T>() where T : LcObject
        {
            var obj = (T)Activator.CreateInstance(typeof(T));
            obj.Initilize(this);
            return obj;
        }

        public T CreateObject<T>(params object[] args) where T : LcObject
        {
            var obj = (T)Activator.CreateInstance(typeof(T), args);
            obj.Initilize(this);
            return obj;
        }

        public void SetActiveViewport(LcViewport viewport)
        {
            foreach (var vport in this.ActiveLayout.Viewports)
            {
                if (vport == viewport)
                {
                    vport.IsActive = true;
                    ActiveViewport = vport;
                }
                else
                {
                    vport.IsActive = false;
                }
            }
        }

        public void SetActiveViewport(long viewportId)
        {
            foreach (var vport in this.ActiveLayout.Viewports)
            {
                if (vport.Id == viewportId)
                {
                    vport.IsActive = true;
                    ActiveViewport = vport;
                }
                else
                {
                    vport.IsActive = false;
                }
            }
        }

        public void SetActiveLayout(LcLayout layout)
        {
            foreach (var lyt in this.Layouts)
            {
                lyt.IsActive = false;
            }

            layout.IsActive = true;
            ActiveLayout = layout;
            SetActiveViewport(layout.Viewports[0]);
        }

        private void InitLayouts()
        {
            this.Layouts = new LayoutCollection();

            var layout = this.CreateObject<LcLayout>();
            layout.Set("默认视口布局", LayoutType.One);
            this.Layouts.Add(layout);

            //layout = this.CreateObject<LcLayout>();
            //layout.Set("左右视口布局", LayoutType.HorzTwo);
            //this.Layouts.Add(layout);

            //layout = this.CreateObject<LcLayout>();
            //layout.Set("上下视口布局", LayoutType.VertTwo);
            //this.Layouts.Add(layout);

            //layout = this.CreateObject<LcLayout>();
            //layout.Set("四个视口布局", LayoutType.Four);
            //this.Layouts.Add(layout);

            SetActiveLayout(this.Layouts[0]);
            SetActiveViewport(this.ActiveLayout.Viewports[0]);
        }

        /// <summary>
        /// 加载默认线型
        /// </summary>
        private void InitLineTypes()
        {
            this.LineTypes = new LcLineTypeCollection();
            var ByLayer = this.CreateObject<LcLineType>();
            byte[] buffer = Guid.NewGuid().ToByteArray();
            int ByLayerid = (int)BitConverter.ToInt64(buffer, 0);
            ByLayer.Id = ByLayerid;
            ByLayer.LineTypeName = "ByLayer";
            ByLayer.LineTypeExplain = "";
            ByLayer.LineTypeDefinition = "";

            var ByBlock = this.CreateObject<LcLineType>();
            byte[] ByBlockbuffer = Guid.NewGuid().ToByteArray();
            int ByBlockid = (int)BitConverter.ToInt64(ByBlockbuffer, 0);
            ByBlock.Id = ByBlockid;
            ByBlock.LineTypeName = "ByBlock";
            ByBlock.LineTypeExplain = "";
            ByBlock.LineTypeDefinition = "";

            var Continuous = this.CreateObject<LcLineType>();
            byte[] Continuousbuffer = Guid.NewGuid().ToByteArray();
            int Continuousid = (int)BitConverter.ToInt64(Continuousbuffer, 0);
            Continuous.Id = Continuousid;
            Continuous.LineTypeName = "Continuous";
            Continuous.LineTypeExplain = "Continuous";
            Continuous.LineTypeDefinition = "";
            LineTypes.Add(ByLayer);
            LineTypes.Add(ByBlock);
            LineTypes.Add(Continuous);
        }
       

        private void InitPapers()
        {
            var paper1 = this.CreateObject<LcPaper>();
            paper1.Name = "图纸1";
            this.PaperSpace.Papers.Add(paper1);

            var paper2 = this.CreateObject<LcPaper>();
            paper2.Name = "图纸2";
            this.PaperSpace.Papers.Add(paper2);
        }

        /// <summary>
        /// 初始化文档对象，JSON序列化不需要调用
        /// </summary>
        public void Initialize()
        {
            this.Uuid = Guid.NewGuid().ToString();
            this.Info = this.CreateObject<LcDocumentInfo>();
            this.ProjectInfo = this.CreateObject<LcProjectInfo>();

            this.ModelSpace = new LcModelSpace(this);
            this.InitLayouts();

            this.PaperSpace = new LcPaperSpace(this);
            this.InitPapers();

            this.InitLayers();
            this.InitLineTypes();
            //if (ObjectPropsDefMap == null)
            //{
            //    ObjectPropsDefMap = new ObjectPropertiesDefinitionMap();

            //    var sumProps = new ObjectPropertiesDefinition("LightCAD.SummaryInfo");
            //    var propGrp = sumProps.AddGroup("QdDocument", "启道协同-文档信息");
            //    propGrp.PropDefs.Add(new PropertyDefinition { Name = "Attr1", Display = "属性1" });
            //    ObjectPropsDefMap.Add(sumProps);

            //    var prjProps = new ObjectPropertiesDefinition("LightCAD.ProjectInfo");
            //    propGrp = prjProps.AddGroup("QdProject", "启道协同-项目信息");
            //    propGrp.PropDefs.Add(new PropertyDefinition { Name = "Attr2", Display = "属性2" });
            //    ObjectPropsDefMap.Add(prjProps);

            //}
        }

        private void InitLayers()
        {
            var layer0 = this.CreateObject<LcLayer>();
            layer0.Name = "0";
            layer0.Color = 0xFF00FF00;
            layer0.Transparency = 0;
            this.Layers.Add(layer0);
        }

        private void BuildStruct()
        {
            this.ModelSpace.Document = this;
            if (this.ModelSpace.Elements.Count > 0)
            {
                foreach (var ele in this.ModelSpace.Elements)
                {
                    ele.Document = this;
                    IdCreator.RestObjectIdMax(ele.Id);
                }
            }

            this.PaperSpace.Document = this;
        }


        #region evets 文档操作提供以下四个基本事件

        // 对象本身发生变化
        public event EventHandler<ObjectChangedEventArgs> ObjectChangedBefore;
        public event EventHandler<ObjectChangedEventArgs> ObjectChangedAfter;

        // 对象的属性发生变化
        public event EventHandler<PropertyChangedEventArgs> PropertyChangedBefore;
        public event EventHandler<PropertyChangedEventArgs> PropertyChangedAfter;


        public void OnPropertyChangedBefore(PropertyChangedEventArgs args)
        {
            PropertyChangedBefore?.Invoke(this, args);
        }

        public void OnPropertyChangedAfter(PropertyChangedEventArgs args)
        {
            PropertyChangedAfter?.Invoke(this, args);
        }

        public void OnObjectChangedBefore(ObjectChangedEventArgs args)
        {
            ObjectChangedBefore?.Invoke(this, args);
        }

        public void OnObjectChangedAfter(ObjectChangedEventArgs args)
        {
            ObjectChangedAfter?.Invoke(this, args);
        }

        public static void RegistElementTypes(params ElementType[] elementTypes)
        {
            foreach (var eleType in elementTypes)
            {
                try
                {
                    ElementTypes.Add(eleType);
                }
                catch (Exception ex)
                {
                    throw new Exception($"Guid of {eleType.Name} is  repeated.");
                }
            }
        }

        public LcElement CreateElement(string typeName,string baseType)
        {
            foreach (var eleType in ElementTypes)
            {
                if (eleType.Name == typeName)
                {
                    var ele = (LcElement)Activator.CreateInstance(eleType.ClassType);
                    ele.Document = this;
                    return ele;
                }
            }
            //如果发现没有匹配类型的元素
            if(baseType == nameof(DirectComponent))
            {
                return null;
                //var ele = new DirectComponent();
                //ele.Document = this;
                //return ele;
            }
            else if(baseType==nameof(LcComponentInstance))
            {
                var ele = new LcComponentInstance(null);
                ele.Document = this;
                return ele;
            }
            else
            {
                throw new Exception($"Can't create element type.{typeName}");
            }
        }


        public LcElement CreateElement(string typeName, string baseType, params object[] args)
        {
            foreach (var eleType in ElementTypes)
            {
                if (eleType.Name == typeName)
                {
                    var ele = (LcElement)Activator.CreateInstance(eleType.ClassType, args);
                    ele.Document = this;
                    return ele;
                }
            }
            //如果发现没有匹配类型的元素
            if (baseType == nameof(DirectComponent))
            {
                return null;
                //var ele = new DirectComponent();
                //ele.Document = this;
                //return ele;
            }
            else if (baseType == nameof(LcComponentInstance))
            {
                var ele = new LcComponentInstance(null);
                ele.Document = this;
                return ele;
            }
            else
            {
                throw new Exception($"Can't create element type.{typeName}");
            }
        }

        public static void ResetObjectRelation<T>(List<T> objs) where T : LcObject
        {
            foreach (var obj in objs)
            {
                obj.ReadObjectRefs(objs);
            }
        }

        #endregion
    }
}